﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;

namespace FusionDotNet
{
    /// <summary>
    /// Base implementation of commands that require an HTTP POST such as INSERT.
    /// </summary>
    /// <typeparam name="TResult">Type of <seealso cref="CommandResult"/> that this command returns.</typeparam>
    public abstract class PostCommand<TResult> : Command<TResult> where TResult : CommandResult, new()
    {
        private const int BLOCK_SIZE = 10240;

        /// <summary>
        /// Contains the data used in the body of the HTTP POST.
        /// </summary>
        protected byte[] PostContent { get; set; }

        /// <summary>
        /// Create the <see cref="HttpWebRequest"/> for the POST operation.
        /// </summary>
        /// <returns></returns>
        protected override HttpWebRequest CreateWebRequest()
        {
            HttpWebRequest webRequest =  base.CreateWebRequest();
            webRequest.Method = Constants.WEB_METHOD_POST;
            webRequest.ContentType = Constants.CONTENT_TYPE_APPLICATION_URLENCODED;
            webRequest.ContentLength = GetContentLength();
            return webRequest;
        }

        /// <summary>
        /// Specifies the length of the content stream in bytes.
        /// </summary>
        /// <returns></returns>
        protected virtual long GetContentLength()
        {
            return PostContent.LongLength;
        }

        /// <summary>
        /// Returns a Stream object containing the POST data.
        /// </summary>
        /// <returns>Stream containing the POST data.</returns>
        protected virtual Stream GetContent()
        {
            return new MemoryStream(PostContent);            
        }

        /// <summary>
        /// Synchronously executes the POST operation.
        /// </summary>
        /// <returns>Stream containing the results of the POST operation.</returns>
        protected override System.IO.Stream ExecuteCommand()
        {
            HttpWebRequest request = CreatePostRequest();

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            CheckForLoginRedirect(request, response);

            return response.GetResponseStream();
        }

        /// <summary>
        /// Creates and configure the HttpWebRequest for the POST operation. This call uses <see cref="CreatePostRequest"/> to create the HttpWebRequest and then writes the results of <see cref="GetContent"/> to the request stream.
        /// </summary>
        /// <returns></returns>
        private HttpWebRequest CreatePostRequest()
        {
            HttpWebRequest request = CreateWebRequest();
            Stream requestStream = request.GetRequestStream();
            Stream contentBuffer = GetContent();

            while (contentBuffer.Position != contentBuffer.Length)
            {
                byte[] copyBuffer = new byte[BLOCK_SIZE];
                int bytesRead = contentBuffer.Read(copyBuffer, 0, BLOCK_SIZE);
                requestStream.Write(copyBuffer, 0, bytesRead);
            }
            return request;
        }

        /// <summary>
        /// Asynchronously execute the POST command.
        /// </summary>
        protected override void ExecuteCommandAsync()
        {
            HttpWebRequest request = CreatePostRequest();

            RequestState state = new RequestState(request);

            IAsyncResult result = request.BeginGetResponse(this.ExecuteComplete, state);

            if (result.CompletedSynchronously)
            {
                IsBusy = false;
            }
            else
            {
                IsBusy = true;
            }
        }

    }
}
